using System;
using System.IO;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Threading;
using System.Security.Principal;
using System.Security.Cryptography;

namespace BEGalleryExtension
{
    public class PhotoInformation
    {
        PhotoDataSet data = new PhotoDataSet();
        HttpContext context = null;
        DirectoryInfo baseDir = null;
        public PhotoInformation()
        {
            context = HttpContext.Current;
            baseDir = new DirectoryInfo(context.Server.MapPath("~/App_Data/gallery"));
            data = (PhotoDataSet)context.Cache["photoData"];
            if (data == null)
            {
                data = new PhotoDataSet();
                data.ReadXmlSchema(Path.Combine(baseDir.FullName, "PhotoDataSet.xsd"));
                FileInfo finfo = new FileInfo(Path.Combine(baseDir.FullName, "PhotoGallery.xml"));
                if (finfo.Exists)
                    data.ReadXml(finfo.FullName);
                context.Cache["photoData"] = data;
            }
        }

        public DataTable getDirectories(int parentID)
        {
            DataTable table = new DataTable();
            table.Columns.Add("ID");
            table.Columns.Add("DirectoryName");

            DataRow[] rows = data.Directories.Select("ParentID=-1");
            if (parentID != 0)
                rows = data.Directories.Select("ParentID=" + parentID);

            table.Rows.Add(new object[] { getParent(parentID), "Up a level" });
            foreach (DataRow row in rows)
                table.ImportRow(row);

            return table;
        }

        private int getParent(int directoryID)
        {
            DataRow[] rows = data.Directories.Select("ID=" + directoryID);
            if (rows.Length == 0)
                return -1;

            PhotoDataSet.DirectoriesRow drow = (PhotoDataSet.DirectoriesRow)rows[0];
            return drow.ParentID;
        }

        public DataTable getPhotos(int directoryID)
        {
            DataTable table = new DataTable();
            table.Columns.Add("ID");
            table.Columns.Add("FileName");

            DataRow[] rows = data.Photos.Select("DirectoryID=" + directoryID);
            foreach (DataRow row in rows)
                table.ImportRow(row);

            return table;
        }

        public void insertPhoto(DirectoryInfo dir, string file)
        {
            FileInfo finfo = new FileInfo(Path.Combine(dir.FullName, file));
            string hashKey = getMD5(finfo);

            int parentID = insertDirectory(dir);
            DataRow[] rows = data.Photos.Select("DirectoryID=" + parentID + " and FileName='" + file + "'");
            if (rows.Length == 0)
                data.Photos.AddPhotosRow(parentID, file, hashKey);
        }

        private string getMD5(FileInfo finfo)
        {
            byte[] hashValue;
            FileStream fs = new FileStream(finfo.FullName, FileMode.Open);
            MD5CryptoServiceProvider hashFunction = new MD5CryptoServiceProvider();

            hashValue = hashFunction.ComputeHash(fs);
            fs.Close();

            return BitConverter.ToString(hashValue).Replace("-", "");
        }

        public int insertDirectory(DirectoryInfo dir)
        {
            if (dir == null)
                return -1;

            if (dir.FullName == baseDir.FullName)
                return -1;

            DataRow[] rows = data.Directories.Select("DirectoryName='" + dir.Name + "'");
            if (rows.Length == 0)
            {
                PhotoDataSet.DirectoriesRow drow = data.Directories.AddDirectoriesRow(insertDirectory(dir.Parent), dir.Name);
                return drow.ID;
            }
            else if (rows.Length == 1)
            {
                PhotoDataSet.DirectoriesRow drow = (PhotoDataSet.DirectoriesRow)rows[0];
                return drow.ID;
            }

            DirectoryInfo parent = dir.Parent;
            foreach (PhotoDataSet.DirectoriesRow row in rows)
            {
                DataRow[] drows = data.Directories.Select("ID=" + Convert.ToInt32(row.ParentID));
                if (drows.Length == 1)
                {
                    PhotoDataSet.DirectoriesRow drow = (PhotoDataSet.DirectoriesRow)drows[0];
                    if (drow.DirectoryName.Equals(parent.Name))
                        return drow.ID;
                }
            }

            return -1;
        }

        public void CreateInitialSecurity()
        {
            string[] roles = Roles.GetAllRoles();
            foreach (PhotoDataSet.DirectoriesRow drow in data.Directories.Rows)
                foreach (string role in roles)
                    addDirectorySecurity(role, drow.ID, true);
        }

        public bool canRead(int directoryID)
        {
            DataRow[] rows = data.DirectorySecurity.Select("DirectoryID=" + directoryID);
            // Many to Many comparrison of rows vs. Roles.GetUserRoles(username)

            return true;
        }

        public void addDirectorySecurity(string role, int directoryID, bool read)
        {
            DataRow[] rows = data.DirectorySecurity.Select("DirectoryID=" + directoryID + " and RoleName='" + role + "'");
            if (rows.Length == 0)
            {
                data.DirectorySecurity.AddDirectorySecurityRow(role, directoryID, read);
            }
            else
            {
                foreach (PhotoDataSet.DirectorySecurityRow drow in rows)
                {
                    drow.BeginEdit();
                    drow.Read = read;
                    drow.AcceptChanges();
                }
            }
        }

        public void Save()
        {
            data.WriteXml(Path.Combine(baseDir.FullName, "PhotoGallery.xml"));
        }

        public string getPhotoLocationFromID(int id)
        {
            string path = baseDir.FullName;
            DataRow[] rows = data.Photos.Select("ID=" + id);
            if (rows.Length == 1)
            {
                PhotoDataSet.PhotosRow prow = (PhotoDataSet.PhotosRow)rows[0];
                path = Path.Combine(getDirPathFromParent(prow.DirectoryID, ""), prow.FileName);
            }

            return path;
        }

        public int getRandomPhotoID()
        {
            int max = data.Photos.Count;
            Random rnd = new Random();
            return rnd.Next(0, max);
        }

        public int getNextPhoto(int directoryID, int photoID)
        {
            DataTable table = getPhotos(directoryID);
            return getPhotoIDs(table.DefaultView, photoID, 1);
        }

        public int getPrevPhoto(int directoryID, int photoID)
        {
            DataTable table = getPhotos(directoryID);
            return getPhotoIDs(table.DefaultView, photoID, -1);
        }

        // Helper function for getNextPhoto() and getPrevPhoto()
        // Need a better way to do this
        private int getPhotoIDs(DataView view, int photoID, int offset)
        {
            view.Sort = "ID asc";
            DataTable table = view.Table;
            int index = -1;

            for (int x = 0; x < table.Rows.Count; x++)
            {
                int tmp = -1;
                Int32.TryParse(Convert.ToString(table.Rows[x]["ID"]), out tmp);
                if (tmp == photoID)
                {
                    index = x;
                    break;
                }
            }

            index += offset;

            if (index < 0 || index > (table.Rows.Count - 1))
                return photoID;

            Int32.TryParse(Convert.ToString(table.Rows[index]["ID"]), out index);
            return index;
        }

        public string getPhotoNameFromID(int id)
        {
            string fileName = "";
            DataRow[] rows = data.Photos.Select("ID=" + id);
            if (rows.Length == 1)
            {
                PhotoDataSet.PhotosRow prow = (PhotoDataSet.PhotosRow)rows[0];
                fileName = prow.FileName;
            }

            return fileName;
        }

        private string getDirPathFromParent(int directoryID, string path)
        {
            string opath = path;
            DataRow[] rows = data.Directories.Select("ID=" + directoryID);
            if (rows.Length == 1)
            {
                PhotoDataSet.DirectoriesRow drow = (PhotoDataSet.DirectoriesRow)rows[0];
                opath = Path.Combine(drow.DirectoryName, opath);
                return getDirPathFromParent(drow.ParentID, opath);
            }

            return opath;
        }
    }
}
